/**
 * @file drv_can.c
 * @brief CAN总线驱动
 * @date 2025-11-03
 */

#include "user_config.h"
#include "drv_can.h"
#include "sys_manager.h"
#include "nst_msg.h"
#include "can.h"
#include "stm32f0xx_hal.h"
#include "stm32f0xx_hal_can.h"
#include <string.h>

/* 外部变量声明（来自 CubeMX生成的can.c） */
extern CAN_HandleTypeDef hcan;

/* 私有变量定义 ---------------------------------------------------------*/
#define CAN_RX_QUEUE_SIZE   16  /* CAN接收队列大小 */

static nst_msg_queue_t s_can_rx_queue;
static uint8_t s_can_rx_buffer[sizeof(can_message_t) * CAN_RX_QUEUE_SIZE];

/**
 * @brief 初始化CAN
 */
int drv_can_init(void)
{
    /* 初始化接收队列 */
    nst_msg_init(&s_can_rx_queue, "CAN_RX", s_can_rx_buffer,
                 sizeof(can_message_t), CAN_RX_QUEUE_SIZE);

    /* CAN已在MX_CAN_Init()中完成初始化、滤波器配置、启动和中断激活 */
    /* 这里只需初始化接收队列即可 */

    return 0;
}

/**
 * @brief 发送CAN消息
 */
int drv_can_send(uint32_t id, uint8_t *data, uint8_t len)
{
    CAN_TxHeaderTypeDef tx_header;
    uint32_t tx_mailbox;

    if (data == NULL || len == 0 || len > 8)
    {
        return -1;
    }

    /* 检查是否有空闲的发送邮箱 */
    if (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) == 0)
    {
        return -1;  /* 所有邮箱都忙，发送失败 */
    }

    tx_header.StdId = id;
    tx_header.ExtId = 0;
    tx_header.RTR = CAN_RTR_DATA;
    tx_header.IDE = CAN_ID_STD;
    tx_header.DLC = len;
    tx_header.TransmitGlobalTime = DISABLE;

    if (HAL_CAN_AddTxMessage(&hcan, &tx_header, data, &tx_mailbox) != HAL_OK)
    {
        return -1;
    }

    return 0;
}

/**
 * @brief 检查是否有消息
 */
bool drv_can_available(void)
{
    return !nst_msg_is_empty(&s_can_rx_queue);
}

/**
 * @brief 读取消息
 */
int drv_can_read(can_message_t *msg)
{
    if (msg == NULL)
    {
        return -1;
    }

    if (nst_msg_dequeue(&s_can_rx_queue, msg))
    {
        return 0;
    }

    return -1;
}

/* CAN接收中断回调 -------------------------------------------------------*/

/**
 * @brief CAN接收中断
 */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan_ptr)
{
    CAN_RxHeaderTypeDef rx_header;
    can_message_t rx_msg;

    if (HAL_CAN_GetRxMessage(hcan_ptr, 0x00000000U, &rx_header, rx_msg.data) == HAL_OK)
    {
        rx_msg.id = rx_header.StdId;
        rx_msg.len = rx_header.DLC;

        /* 将所有CAN消息入队（板号分配不通过CAN接收，只通过AD_DET） */
        nst_msg_enqueue(&s_can_rx_queue, &rx_msg);
    }
}

/******************************** 文件结束 *********************************/
